import traceback
from datetime import datetime
from typing import Annotated

from fastapi import Depends
from sqlalchemy import and_, delete, func, insert, select, update

from forward.api.admin.orm.lucky.activity import ActivityORM
from forward.api.admin.orm.lucky.activity_prize import ActivityPrizeORM
from forward.api.admin.orm.lucky.prize import PrizeORM
from forward.api.admin.schemas.lucky.prize import (
    PrizeAddInSchema,
    PrizeDeleteInSchema,
    PrizeDetailInSchema,
    PrizeEditInSchema,
    PrizeListInSchema,
    PrizeStatusInSchema,
)
from forward.common.enums import ActivityStatusEnum
from forward.dependencies.database import db
from forward.exceptions.base import AppException
from forward.extend.pydantic.result_api import ResultAPI
from forward.http_base import HttpResp
from forward.model.schemas.lucky.prize import PrizeOutSchema
from forward.model.tables.activity import ActivityModel, PrizeModel
from forward.utils.urls import UrlUtil


class PrizeService:
    def __init__(
        self,
        prize_orm: Annotated[PrizeORM, Depends()],
        activity_prize_orm: Annotated[ActivityPrizeORM, Depends()],
        activity_orm: Annotated[ActivityORM, Depends()],
    ):
        self.prize_orm = prize_orm
        self.activity_prize_orm = activity_prize_orm
        self.activity_orm = activity_orm

    async def lists(self, list_in: PrizeListInSchema):
        try:
            where = []
            statement = (
                select(PrizeModel)
                .where(*where)
                .where(PrizeModel.is_deleted == 0)
                .order_by(PrizeModel.id.desc())
                .limit(list_in.page_size)
                .offset((list_in.page_num - 1) * list_in.page_size)
            )
            records = await db.fetch_all(statement)
            statement_count = select(func.count(PrizeModel.id)).where(*where)
            count = await db.fetch_val(statement_count)
            lists = [
                PrizeOutSchema.model_validate(record, from_attributes=True)
                for record in records
            ]
            for item in lists:
                if item.img:
                    item.img = await UrlUtil.to_absolute_url(item.img)
            return ResultAPI(data={"lists": lists, "count": count})
        except Exception as e:
            print(f"Database error in add: {e}")
            traceback.print_exc()
            raise

    async def add(self, add_in: PrizeAddInSchema):
        if add_in.img:
            add_in.img = await UrlUtil.to_relative_url(add_in.img)
        statement = insert(PrizeModel).values(add_in.model_dump())
        await db.execute(statement)
        return ResultAPI()

    async def edit(self, edit_in: PrizeEditInSchema):
        if edit_in.img:
            edit_in.img = await UrlUtil.to_relative_url(edit_in.img)
        statement = (
            update(PrizeModel)
            .where(PrizeModel.id == edit_in.id)
            .values(edit_in.model_dump())
        )
        await db.execute(statement)
        return ResultAPI()

    async def detail(self, detail_in: PrizeDetailInSchema):
        statement = select(PrizeModel).where(PrizeModel.id == detail_in.id)
        record = await db.fetch_one(statement)
        prize = PrizeOutSchema.model_validate(record, from_attributes=True)
        if prize.img:
            prize.img = await UrlUtil.to_absolute_url(prize.img)
        return ResultAPI(data=prize)

    async def delete(self, delete_in: PrizeDeleteInSchema):
        """
        删除奖品
        logic：
        1，检测是否绑定有活动，这个活动是否在进行时（上架，有效期）任意一个不满足就报错
        2，删除奖品
        """
        activity_prize_list = await self.activity_prize_orm.get_all_by_filters(
            prize_id=delete_in.id
        )
        activity_ids_map = map(lambda x: x.activity_id, activity_prize_list)
        where = and_(
            ActivityModel.id.in_(activity_ids_map),
            ActivityModel.status == 1,
            ActivityModel.start_time <= datetime.now(),
            ActivityModel.end_time >= datetime.now(),
        )
        activity_list = await self.activity_orm.get_all_by_filters(where=where)
        if activity_list:
            raise AppException(
                HttpResp.FAILED, msg="奖品已被活动绑定，请先解除绑定再删除!"
            )
        statement = (
            update(PrizeModel).where(PrizeModel.id == delete_in.id).values(is_deleted=1)
        )
        await db.execute(statement)
        return ResultAPI()

    async def status(self, status_in: PrizeStatusInSchema):
        statement = (
            update(PrizeModel)
            .where(PrizeModel.id == status_in.id)
            .values(status_in.model_dump())
        )
        await db.execute(statement)
        return ResultAPI()
